package com.chenyaowei.payment.service.impl;


import com.alibaba.fastjson2.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConstants;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.*;
import com.alipay.api.response.*;
import com.chenyaowei.common.exception.ServiceException;
import com.chenyaowei.common.utils.DateUtils;
import com.chenyaowei.order.domain.CywOrder;
import com.chenyaowei.order.domain.CywOrderItem;
import com.chenyaowei.order.service.ICywOrderItemService;
import com.chenyaowei.order.service.ICywOrderService;
import com.chenyaowei.payment.config.AlipayConfig;
import com.chenyaowei.payment.domain.CywPaymentInfo;
import com.chenyaowei.payment.request.OrderReturnRequest;
import com.chenyaowei.payment.service.AlipayService;
import com.chenyaowei.payment.service.ICywPaymentInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class AlipayServiceImpl implements AlipayService {

    @Autowired
    private Environment env;

    @Autowired
    private ICywOrderService orderService;

    @Autowired
    private ICywOrderItemService orderItemService;

    @Autowired
    private ICywPaymentInfoService paymentInfoService;

    @Autowired
    private AlipayClient alipayClient;

    private static final Logger log = LoggerFactory.getLogger(AlipayServiceImpl.class);

    /**
     * 统一收单交易关闭接口，关闭订单
     */
    @Override
    public String closeOrder(String orderSn) {
        try {
            AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", orderSn);
            request.setBizContent(bizContent.toString());
            AlipayTradeCloseResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                log.info("关闭订单调用成功" + response.getBody());
            } else {
                log.error("关闭订单调用失败" + response.getBody());
            }
            return response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        throw new ServiceException("统一收单交易关闭接口,调用失败");
    }

    /**
     * 统一收单交易查询
     */
    @Override
    public String queryOrder(String orderSn) {
        try {
            AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("trade_no", "orderSn");
            request.setBizContent(bizContent.toString());
            AlipayTradeQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                log.info("关闭订单调用成功" + response.getBody());
            } else {
                log.error("关闭订单调用失败" + response.getBody());
            }
            return response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        throw new ServiceException("统一收单交易查询接口,调用失败");
    }

    /**
     * 统一收单交易退款接口
     */
    @Override
    public String refundOrder(OrderReturnRequest orderReturnRequest) {
        try {
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", orderReturnRequest.getOrderSn());
            bizContent.put("refund_amount", orderReturnRequest.getRefundAmount());
            bizContent.put("refund_reason", orderReturnRequest.getRefundReason());
            //退款请求号。 标识一次退款请求，需要保证在交易号下唯一，如需部分退款，则此参数必传。 注：针对同一次退款请求，如果调用接口失败或异常了，重试时需要保证退款请求号不能变更，防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
            //bizContent.put("out_request_no", "HZ01RF001");

            // 返回参数选项，按需传入
            //JSONArray queryOptions = new JSONArray();
            //queryOptions.add("refund_detail_item_list");
            //bizContent.put("query_options", queryOptions);

            request.setBizContent(bizContent.toString());
            AlipayTradeRefundResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                System.out.println("调用成功");
                //TODO 处理退款业务逻辑
            } else {
                System.out.println("调用失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 统一收单交易退款查询
     */
    @Override
    public String queryReturnOrder(String orderSn) {
        try {
            AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
            JSONObject bizContent = new JSONObject();
            bizContent.put("trade_no", "orderSn");
            request.setBizContent(bizContent.toString());
            AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                log.info("关闭订单调用成功" + response.getBody());
            } else {
                log.error("关闭订单调用失败" + response.getBody());
            }
            return response.getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        throw new ServiceException("统一收单交易查询接口,调用失败");
    }

    /**
     *  统一收单下单并支付页面接口
     *  https://open.alipay.com/api/apiDebug?frontProdCode=I1080300001000041203&backProdCode=I1011000100000000005
     **/
    @Override
    public String payOrder(String orderSn){
        try {
            CywOrder order = orderService.selectOrderByOrderSn(orderSn);
            List<CywOrderItem> orderItems = orderItemService.selectListByOrderSn(orderSn);
            StringBuilder subject = new StringBuilder();
            orderItems.forEach(item -> {
                subject.append(item.getSpuName()).append("、");
            });

            AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
            //异步接收地址，仅支持http/https，公网可访问
            request.setNotifyUrl(AlipayConfig.getNotifyUrl());
            //同步跳转地址，仅支持http/https
            request.setReturnUrl(AlipayConfig.getReturnUrl());
            /******必传参数******/
            JSONObject bizContent = new JSONObject();
            //商户订单号，商家自定义，保持唯一性
            bizContent.put("out_trade_no", orderSn);
            //支付金额，最小值0.01元
            bizContent.put("total_amount", order.getPayAmount().toString());
            //订单标题，不可使用特殊符号
            bizContent.put("subject", subject.substring(0, subject.length() - 1));
            //订单的最晚付款时间, 过期，交易关闭。
            SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//            Date timeExpire = new Date(order.getCreateTime().getTime() + 1000 * 60 * 5);
            Date timeExpire = DateUtils.addMinutes(order.getCreateTime(), 15);
            //订单绝对超时时间。2016-12-31 10:05:01
            bizContent.put("time_expire", sf.format(timeExpire));
            //电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAY
            bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");

            request.setBizContent(bizContent.toString());
            AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
            System.out.println(response.getBody());
            if (response.isSuccess()) {
                log.info("支付成功" + response.getBody());
                return response.getBody();
            } else {
                // sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
                // String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
                // System.out.println(diagnosisUrl);
                log.error("支付接口调用失败" + response.getBody());
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        throw new ServiceException("统一收单下单并支付页面接口,调用失败");
    }

    /**
     * 支付成功异步通知
     * https://opendocs.alipay.com/open/270/105902?pathHash=d5cd617e
     */
    @Override
    public String handleAlipayed(Map<String, String> params) {
        log.info("支付通知正在执行");
        log.info("通知参数 ===> {}", params);
        String result = "failure";
        try {
            //异步通知验签,调用SDK验证签名
            boolean signVerified = AlipaySignature.rsaCheckV1(
                    params,
                    env.getProperty("alipay.publicKey"),
                    AlipayConstants.CHARSET_UTF8,
                    AlipayConstants.SIGN_TYPE_RSA2);

            if (!signVerified) {
                //验签失败则记录异常日志，并在response中返回failure.
                log.error("支付成功异步通知验签失败！");
                return result;
            }

            // 验签成功后
            log.info("支付成功异步通知验签成功！");

            //按照支付结果异步通知中的描述，对支付结果中的业务内容进行二次校验，

            //3 校验通知中的 seller_id（或者 seller_email) 是否为 out_trade_no 这笔单据的对应的操作方
            String sellerId = params.get("seller_id");
            String sellerIdProperty = env.getProperty("alipay.sellerId");
            if (!sellerId.equals(sellerIdProperty)) {
                log.error("商家账号（PID）校验失败");
                return result;
            }

            //4 验证 app_id 是否为该商户本身
            String appId = params.get("app_id");
            String appIdProperty = env.getProperty("alipay.appId");
            if (!appId.equals(appIdProperty)) {
                log.error("appid校验失败");
                return result;
            }

            //在支付宝的业务通知中，只有交易通知状态为 TRADE_SUCCESS时，
            // 支付宝才会认定为买家付款成功。
/*
            String tradeStatus = params.get("trade_status");
            if (!"TRADE_SUCCESS".equals(tradeStatus)) {
                log.error("支付未成功");
                return result;
            }
*/

            //1 商户需要验证该通知数据中的 out_trade_no 是否为商户系统中创建的订单号
            String orderSn = params.get("out_trade_no");
            CywOrder order = orderService.selectOrderByOrderSn(orderSn);
            if (order == null) {
                log.error("订单不存在");
                return result;
            }
            //2 判断 total_amount 是否确实为该订单的实际金额（即商户订单创建时的金额）
            String total_amount = params.get("total_amount");
            String discountedPrice = order.getPayAmount().toString();
            if (!total_amount.equals(discountedPrice)) {
                log.error("金额校验失败");
                return result;
            }
            //处理业务 修改订单状态 记录支付日志
            result = handlePayResult(params, order);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return result;
    }

    private String handlePayResult(Map<String, String> params, CywOrder order) {
        //1、保存交易流水
        CywPaymentInfo paymentInfo = new CywPaymentInfo();
        paymentInfo.setAlipayTradeNo(params.get("trade_no"));
        String orderSn = params.get("out_trade_no");
        paymentInfo.setOrderSn(orderSn);
        String tradeStatus = params.get("trade_status");
        paymentInfo.setPaymentStatus(tradeStatus);
        paymentInfo.setCallbackTime(DateUtils.parseDate(params.get("notify_time")));
        paymentInfoService.insertCywPaymentInfo(paymentInfo);
        //2.修改订单的状态
        if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED")){
            orderService.handlePayResult(orderSn);
        }
        return "success";
    }

}
